
/// MLSDEFORMER source code
/// by Alvaro Cuno, LCG-COPPE-UFRJ
/// bugs? email-me: alvaroecp@gmail.com
/// January, 2007

#ifndef __MESHITEMS_H__
#define __MESHITEMS_H__

#include <CGAL/Polyhedron_items_3.h>
//~ #include <CGAL/HalfedgeDS_default.h>
//~ #include <CGAL/HalfedgeDS_vector.h>
#include <CGAL/HalfedgeDS_decorator.h>
   
template <class Refs, class Traits>
class Vertex : public CGAL::HalfedgeDS_vertex_base<Refs, CGAL::Tag_true, typename Traits::Point_3> {
   
public:
   typedef typename Traits::Vector_3 Vector_3;
   typedef typename Traits::Point_3  Point_3;
   typedef typename CGAL::HalfedgeDS_vertex_base<Refs>::Vertex_handle      Vertex_handle;
   typedef typename CGAL::HalfedgeDS_vertex_base<Refs>::Halfedge_handle    Halfedge_handle;
   
public:
   
   /// Constructors
   Vertex() :
      CGAL::HalfedgeDS_vertex_base< Refs, CGAL::Tag_true, Point_3> () {
      
      _normal = Vector_3(0,0,0);
      _color = Vector_3(0,0,0);
      
      /// variables used for the skinning algorithm
      jointsweights.reserve(20);
      bonesweights.reserve(20);
      ts.reserve(20);
      
      neighbors.reserve(10);
      cots.reserve(10);
      
      /// variables used for the rigging algorithm
      _isKcenter = false;
      kcenterid = 0;
      
      // laplacian parameters
      sapb = 0;
      lfdenom = 1.0;
      lfkterm = 0.0;
      VA = 0;
      
      reset_clustering();
      reset_skinning();
   }
   
   Vertex(const Point_3& p) : 
      CGAL::HalfedgeDS_vertex_base< Refs, CGAL::Tag_true, Point_3> (p) {
      
      _normal = Vector_3(0,0,0);
      _color = Vector_3(0,0,0);
      
      /// variables used for the skinning algorithm
      jointsweights.reserve(20);
      bonesweights.reserve(20);
      ts.reserve(20);
      
      neighbors.reserve(10);
      cots.reserve(10);
      
      /// variables used for the rigging algorithm
      _isKcenter = false;
      kcenterid = 0;
      
      // laplacian parameters
      sapb = 0;
      lfdenom = 1.0;
      lfkterm = 0.0;
      VA = 0;
      
      reset_clustering();
      reset_skinning();
   }
   
   /// Reset variables used for clustering
   void reset_clustering() {
      
      // rigging variables
      correctionFlag = false;
      rigging_group = -1;
      dClosestJoint = 0;
      curr_comp = -1;
      dist_comp = 1e8;
      curr_comp_inter = -1;
      assigned = false;
      d = 1e8;
      next_in_component = -1;
      dPrimSkinRoot = 1e8;
      
      //~ _vertex_parent = -1;
   }
   
   void reset_skinning() {
      
      assigned = false;
      jointsweights.clear();
      bonesweights.clear();
      
      weightlf[0] = 0;
      weightlf[1] = 0;
   }
   
   void previous(const Vertex_handle &v)  { _previous=v; }
   Vertex_handle previous() const { return _previous; }
   
   void previous_hh(const Halfedge_handle &h)  { _previous_hh=h; }
   Halfedge_handle previous_hh() const { return _previous_hh; }
   
   unsigned id() const     { return _id; }
   
   void isKcenter(bool f)  { _isKcenter = f; }
   bool isKcenter() const  { return _isKcenter;}
   float getVoronoiArea()  const { return VA; } //< Returns the Voronoi Area
   float getSumAlphaPlusBeta() const { return sapb; } //< Returns the alpha+beta values for halfedge he
   
   void normal(const Vector_3 &n)  { _normal = n; }
   Vector_3 normal()         const { return _normal; }
   Vector_3 &normal()              { return _normal; }
   
   void color(const Vector_3 &c)  { _color = c; }
   Vector_3 color()         const { return _color; }
   Vector_3 &color()              { return _color; }
   
   //~ void vertex_parent(int id)  { _vertex_parent = id; }
   //~ int vertex_parent()         { return _vertex_parent; }
   
   Vector_3                     _normal;
   Vector_3                     _color;
   
   std::vector<float>            jointsweights;  //< weight of each closest joint 
   std::vector<float>            bonesweights;  //< weight of each closest bone
   std::vector<float>            ts;            //< indicates the closest point to each bones
   
   std::vector<Vertex_handle>    neighbors;   // array of neighbors of this vertex
   std::vector<float>            cots;        // cot(alpha)+cot(beta) values of incident halfedges of this vertex
   
   float                    lfdenom;     // Laplacian filter denominator
   float                    lfkterm;     // Laplacian filter constant term
   float                    VA;          // Stores the Voronoi area for current vertex 
   float                    sapb;        // Stores the summation of alpha and beta values (see the Laplacian coordinates definition)
   float                    weightlf[2]; 
   
   float                    dPrimSkinRoot;
   float                    dClosestJoint;
   float                    d;
   float                    dist_comp;     //< distance to the current connected component of a group or group being processed
   float                    tclosest_bone;
   
   //~ int                      _vertex_parent;   // vertex parent id
   int                      next_in_component;
   int                      rigging_group; //< bone associated to the vertex by the rigging process  /// join? or bone? ... jointgroup
   int                      curr_comp;     //< last connected component or group whose expansion reached the vertex
   int                      curr_comp_inter;
   unsigned                 weight_count;  //< number of bone weights already computed for the vertex
   bool                     assigned;      //< indicates whether the connected component of the vertex has already been found
   
   unsigned int             kcenterid;
   bool                     correctionFlag;
   
private:
public:
   Vertex_handle            _previous;        /// the previous vertex
   Halfedge_handle          _previous_hh;     /// the previous halfedge
   unsigned int             _id;
   bool                     _isKcenter;
};

template <class Refs>
class Halfedge : public CGAL::HalfedgeDS_halfedge_base<Refs> {
   
public:
   Halfedge() :
      hedgeid(-1), alphaplusbeta(0) {
   }
   
   float getAlphaPlusBeta() const { return alphaplusbeta; }
   
   int      hedgeid; // halfedge id
   float    alphaplusbeta; // parameter for Laplacian coordinates computing
};

struct My_items : public CGAL::Polyhedron_items_3 {
   
   template <class Refs, class Traits>
   struct Vertex_wrapper {
      typedef Vertex<Refs, Traits>                       Vertex;
   };
   
   template <class Refs, class Traits>
   struct Halfedge_wrapper {
      typedef Halfedge<Refs>                             Halfedge;
   };
};

#endif
